#ifndef _RANDOM_H_
#define _RANDOM_H_

#include <xmmintrin.h>
#include <emmintrin.h>

class CRandom
{
private:
	union uif
	{
		unsigned long i;
		float f;
	};

	__declspec(align(16)) unsigned long _e[256];
	unsigned char _d;
public:
	inline CRandom():_d(0){}
	inline CRandom(unsigned long s):_d(0){seed(s);}
	inline ~CRandom(){}

	inline void seed(unsigned long seed)
	{
		__m128i xmm1, xmm2, xmm3;
/*
		__m128i xmm1, xmm2, xmm3, xmm4, xmm5, xmm6;
		__m128 xmm7;
*/
		xmm1 = _mm_set1_epi32((int)seed);
		xmm2 = _mm_set_epi32(0xc7439d1e, 0x4a9867b2, 0x385da478, 0xdeadbabe);
		/*
		xmm4 = _mm_set1_epi32(0x007FFFFF);
		xmm5 = _mm_set1_epi32(0x3F800000);
		xmm7 = _mm_set1_ps(-1.0f);
		*/

		for (int i = 0; i < 256; i += 4)
		{
			xmm3 = _mm_xor_si128(xmm1, _mm_srai_epi16(xmm2, 1));
			xmm2 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(3, 0, 1, 2));
			xmm1 = _mm_shuffle_epi32(xmm3, _MM_SHUFFLE(2, 1, 0, 3));
//			xmm6 = _mm_or_si128(_mm_and_si128(xmm3, xmm4), xmm5);
//			_mm_store_ps((float*)&_e[i], _mm_add_ps((__m128&)xmm6, xmm7));
//			_mm_store_ps((float*)&_e[i], (__m128&)xmm3);
			_mm_stream_si128((__m128i*)&_e[i], xmm3);

		}
	}
	inline float rnd()
	{
		uif w;

		w.i = _e[_d];
		_d += 1; // overflow to zero
		if (!_d)
			seed(_e[255]);

		w.i = (w.i & 0x007FFFFF) | 0x3F800000;
		return w.f - 1.0f;

//		return w.f;
	}
	inline float rnd(const float mn, const float mx)
	{
		return (rnd() * (mx - mn)) + mn;
	}
};
#endif //_RANDOM_H_